home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 130_01 / longcode.mac < prev    next >
Text File  |  1985-03-09  |  10KB  |  436 lines

  1. ;                        LONG
  2. ;
  3. ;     LONG is a facility to allow long integers to be
  4. ;   handled in BDS C.  A long integer is a four byte
  5. ;   array with the least significant part of the integer
  6. ;   stored in bytearray[0].  The integer is stored as a
  7. ;   2's complement number with 31 bits of precision.
  8. ;
  9. ;     Operations supported by LONG include addition,
  10. ;   subtraction, multiplication (least significant 31
  11. ;   bits returned), division, and modulus.  Other
  12. ;   operations, such as ascii to long, long to ascii,
  13. ;   etc., can be programmed efficiently in C.
  14. ;
  15. ;     Calls to LONG are normally "wrapped up" in various
  16. ;   C functions which, in turn, call the function
  17. ;
  18. ;        char *li(CODE,arg1,arg2,arg3)
  19. ;        char CODE, *arg1, *arg2, *arg3;
  20. ;
  21. ;   which returns a pointer to the result.  Arg1, arg2,
  22. ;   and arg3 must be pointers to four byte representations
  23. ;   of long integers in the format defined above.  In
  24. ;   general the operation performed is as if BDS C had
  25. ;   a data type long and
  26. ;
  27. ;        long *arg1, *arg2, *arg3;
  28. ;        *arg1 = *arg2 op *arg3;
  29. ;
  30. ;   where op is defined by the following table:
  31. ;
  32. ;         CODE     op      comment
  33. ;
  34. ;           0       +      signed 31 bit result
  35. ;           1       -      signed 31 bit result
  36. ;           2       *      signed low order 31 bit result
  37. ;           3       /      signed 31 bit quotient
  38. ;           4       %      positive 31 bit remainder
  39. ;
  40. ;   and, in each case, any overflow is both lost and not
  41. ;   noted.
  42. ;
  43.     TITLE    LONG
  44. ;
  45.     PAGE    60
  46. ;
  47. ;   BDS C is copyright (c) 1980 by Leor Zolman.
  48. ;   LONG is copyright (c) 1981 by Paul J. Gans.
  49. ;
  50. ;   A notable strangeness in the listing below is that
  51. ;   my version of this assembler REQUIRES that the op
  52. ;   code ex af,af' be CAPITOLIZED or it will not be
  53. ;   recognized...-pjg.
  54. ;
  55.     .z80
  56. ;
  57. ;     Note that the coding technique used here is basically
  58. ;   that of William C. Colley, III as reported in the BDS C
  59. ;   User's Guide Addenda, v1.32, dated May, 1980.  Note
  60. ;   that Colley's technique is simplified by using the
  61. ;   MACRO-80 pseudo-op DC to set the high order bit of
  62. ;   the last character of a string.
  63. ;
  64.     aseg
  65. ;
  66.     org    0000h
  67. ;
  68.     dc    'LI'    ; first directory entry
  69.     dw    long
  70. ;
  71.     db    80h    ; end of directory
  72.     dw    f.free    ; next free file location
  73. ;
  74.     org    0200h
  75. ;
  76.     db    0,0,0,0,0    ; always zero if no main
  77. ;
  78. long:    db    0    ; no fn's called by LONG
  79. ;
  80.     dw    f.1rel-f.1beg    ; length of LONG
  81. ;
  82.     .phase    0
  83. ;
  84. ;   At the start of this function the stack looks like:
  85. ;       arg3, arg2, arg1, CODE, return address
  86. ;   with the return address at the top of the stack.
  87. ;
  88. f.1beg:    pop    de    ; DE=returnaddress
  89.     pop    hl    ; CODE
  90.     ld    a,l    ; A=CODE
  91.     pop    hl    ; HL=arg1 (result address)
  92.     pop    ix    ; IX=arg2
  93.     pop    iy    ; IY=arg3
  94.     push    hl    ; now restore the stack length
  95.     push    hl
  96.     push    hl
  97.     push    hl
  98.     push    de    ; restore return address
  99.     push    bc    ; save BC for caller
  100.     push    hl    ; and a copy of arg1 for later
  101. ;
  102.     exx        ; goto prime register space
  103.     ld    c,(iy+0)    ; low order of args
  104.     ld    b,(iy+1)
  105.     ld    e,(ix+0)
  106.     ld    d,(ix+1)
  107.     ld    hl,0    ; clear result
  108. ;
  109.     exx        ; goto normal register space
  110.     ld    c,(iy+2)    ; high order of args
  111.     ld    b,(iy+3)
  112.     ld    e,(ix+2)
  113.     ld    d,(ix+3)
  114.     ld    hl,0    ; clear result
  115. ;
  116.     cp    0    ; check code
  117. f.1001:    jp    z,add
  118.     cp    1
  119. f.1002:    jp    z,sub
  120.     cp    2
  121. f.1003:    jp    z,mul
  122. ;
  123. ;   The division routine returns two possible values:
  124. ;   the quotient, if CODE was 3, or the modulus, if
  125. ;   CODE was 4.  As a sloppy error exit, CODEs higher
  126. ;   than 4 or lower than 0 default to 4.  I SAID it
  127. ;   was sloppy.
  128. ;
  129. ;   This routine expects a 64 bit dividend in registers
  130. ;   HLH'L'DED'E' and a 32 bit divisor in registers BCB'C'.
  131. ;   A 32 bit quotient is generated in DED'E' and a 32 bit
  132. ;   remainder is generated in HLH'L'.  For the present
  133. ;   application the high order 32 bits of the dividend
  134. ;   (registers HLH'L') are zeroed.
  135. ;
  136. ;
  137. div:    EX    AF,AF'    ; save CODE for later
  138. ;
  139. ;   Because signed divisions are a giant pain, the sign
  140. ;   of the result is computed and saved on the stack.
  141. ;   Then any negative operands are made positive via
  142. ;   calls to the proper routine.
  143. ;
  144. f.1004:    call    sign
  145. ;
  146.     ld    a,32    ; number of iterations
  147. div1:    or    a    ; reset carry flag
  148. ;
  149.     exx        ; enter prime register space
  150.     sbc    hl,bc    ; can we subtract?
  151. ;
  152.     exx        ; enter normal register space
  153.     sbc    hl,bc
  154.     jr    nc,div2    ; a carry means no
  155. ;
  156.     exx        ; enter prime register space
  157.     add    hl,bc    ; restore dividend
  158. ;
  159.     exx        ; enter normal register space
  160.     adc    hl,bc
  161. div2:    ccf        ; quotient bit
  162. ;
  163.     exx        ; enter prime register space
  164.     rl    e    ; left shift dividend, shifting
  165.     rl    d    ;   in new quotient bit as we go
  166. ;
  167.     exx        ; enter normal register space
  168.     rl    e
  169.     rl    d
  170. ;
  171.     exx        ; prime register space
  172.     adc    hl,hl    ; it's a 64 bit shift, guys
  173. ;
  174.     exx        ; normal register space
  175.     adc    hl,hl
  176.     dec    a    ; done?
  177. f.1005:    jp    p,div1    ; no
  178. ;
  179. ;   CODE must now be tested so that HL can be set up
  180. ;   properly.
  181. ;
  182.     EX    AF,AF'    ; regain CODE
  183.     cp    3
  184.     jr    nz,modu    ; it's a modulus by default
  185. ;
  186.     exx        ; prime space
  187.     ex    de,hl    ; return quotient
  188. ;
  189.     exx        ; normal space
  190.     ex    de,hl
  191.     pop    af    ; regain sign of result
  192.     or    a    ; to flags
  193. f.1006:    call    m,neg1    ; if negative
  194. f.1007:    jp    fin    ; to clean up and go home
  195. ;
  196. modu:    srl    h    ; adjust remainder for 1 bit
  197.     rr    l    ;   overshift
  198. ;
  199.     exx        ; prime space
  200.     rr    h
  201.     rr    l
  202. ;
  203.     exx        ; normal space
  204.     pop    de    ; dump saved sign, mod is pos
  205. f.1008:    jp    fin    ; to clean up and go home
  206. ;
  207. ;
  208. ;   The multiplication routine multiplies the contents
  209. ;   of registers BCB'C' by the contents of registers DED'E'
  210. ;   and returns the low order 31 bits of the result in
  211. ;   registers HLH'L'.
  212. ;
  213. ;   Multiplication is also best done on positive numbers,
  214. ;   so we go to the routine again.
  215. ;
  216. mul:    call    sign
  217. ;
  218.     ld    a,32
  219. ;
  220. mul1:    exx        ; enter prime space
  221.     sla    c    ; left shift plier 1 place
  222.     rl    b
  223. ;
  224.     exx        ; enter normal space
  225.     rl    c
  226.     rl    b
  227.     jr    nc,mul2    ; if high bit was 0
  228. ;
  229.     exx        ; prime space
  230.     add    hl,de    ; add in multiplicand
  231. ;
  232.     exx        ; normal space
  233.     adc    hl,de
  234. mul2:    dec    a    ; done?
  235.     jr    z,mul3    ; yes, clean up and go home
  236. ;
  237.     exx        ; hyperspace
  238.     add    hl,hl    ; left shift product
  239. ;
  240.     exx        ; real space
  241.     adc    hl,hl
  242.     jr    mul1    ; and repeat
  243. ;
  244. mul3:    pop    af    ; regain sign of result
  245.     or    a    ; sign to flags
  246. f.1009:    call    m,neg1    ; if negative
  247. f.100a:    jp    fin    ; and so to rest at last...
  248. ;
  249. ;   The contents of BCB'C' are added to the contents of
  250. ;   DED'E' and the results returned in HLH'L'.
  251. ;
  252. add:    exx        ; to prime
  253.     ex    de,hl
  254.     add    hl,bc
  255. ;
  256.     exx        ; to normal
  257.     ex    de,hl
  258.     adc    hl,bc
  259.     jr    fin    ; to quit
  260. ;
  261. ;   The contents of BCB'C' are subtracted from the contents
  262. ;   of DED'E' and the results returned in HLH'L'
  263. ;
  264. sub:    exx        ; to prime
  265.     or    a    ; reset carry flag
  266.     ex    de,hl
  267.     sbc    hl,bc
  268. ;
  269.     exx        ; to normal
  270.     ex    de,hl
  271.     sbc    hl,bc    
  272.     jr    fin    ; to quit
  273. ;
  274. ;   This is the terminal section of code.  It stores the
  275. ;   result from HLH'L' into the locations specified by
  276. ;   arg1, restores BC and SP, and exits with HL containing
  277. ;   arg1.
  278. ;
  279. fin:    pop    ix    ; IX=arg1 (result address)
  280.     pop    bc    ; restore BC while we are at it
  281. ;
  282.     exx        ; to momentum space
  283.     ld    (ix+0),l
  284.     ld    (ix+1),h
  285. ;
  286.     exx        ; to cartesian space
  287.     ld    (ix+2),l
  288.     ld    (ix+3),h
  289.     push    ix    ; get result address
  290.     pop    hl    ;   into HL
  291. ;
  292.     ret        ; to real world
  293. ;
  294. ;   This subroutine computes the sign of the result in
  295. ;   multiplication and division and saves it as bit 7 of
  296. ;   the A register on the stack.  It also makes any
  297. ;   negative operands positive.  Note that it assumes
  298. ;   that HLH'L' are zeroed on entry.
  299. ;
  300. sign:    ld    a,d    ; contains sign of arg2
  301.     xor    b    ; generate result sign
  302.     pop    ix    ; save subs return address
  303.     push    af    ; save result sign
  304. ;
  305.     ld    a,d    ; sign of arg2 again
  306.     or    a    ; to flags
  307. f.100b:    jp    p,sign1    ; if non-negative
  308. ;
  309. ;   Form the 2's complement of the second argument
  310. ;   (DED'E').
  311. ;
  312.     exx        ; far out space
  313.     xor    a    ; reset A and carry bit
  314.     sbc    hl,de
  315.     ex    de,hl    ; restore answer
  316.     ld    l,a    ; clean things up
  317.     ld    h,a
  318. ;
  319.     exx        ; home space
  320.     sbc    hl,de
  321.     ex    de,hl    ; more restore
  322.     ld    l,a    ; clean here too
  323.     ld    h,a
  324. ;
  325. sign1:    ld    a,b    ; sign of arg3
  326.     or     a    ; to flags
  327. f.100c:    jp    p,sign2    ; if non-negative
  328. ;
  329. ;   The two's co